package br.org.reconcavotecnologia.update19.registro;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import br.org.reconcavotecnologia.update19.registro.util.MD5;
import br.org.reconcavotecnologia.update19.registro.util.UtilPropriedades;

/**
 * Classe responsável por gerar o arquivo de metadados do diretório de instalação
 * contendo a listagem dos arquivos e do hash de cada um deles.
 * O hash tem o objetivo informar se o arquivo foi modificado ou não,
 * sendo utilizado para verificar a necessidade de atualização.
 * 
 * @author Cássio Oliveira
 * 
 * @fluxo:
 * 
 * 1. Indica o diretório raiz de instalação para gerar o arquivo update.info
 * 		1.1. Pode indicar a lista de diretórios e/ou arquivos <List(String)> que NÃO devem ser incluídos no update.info
 * 
 * 2. Gera o arquivo update.info
 * 		2.1 Faz a varredura de todos os arquivos indicados
 * 		2.3 Para cada arquivo, gera um HASH
 * 		2.4 Aiciona no update.info a informação do caminho completo e o hash do arquivo 
 */
public class MaquinaHashArquivo {

	/** Mecanismo para escrita e leitura do arquivo property */
	private UtilPropriedades utilProperty = null;

	/** Método contrutor que permite customizar o nome do arquivo update.info*/
	public MaquinaHashArquivo(String updateInfo) {
		this.utilProperty = new UtilPropriedades(updateInfo);
	}

	/** Método construtor padrão. Define o nome do arquivo como update.info*/
	public MaquinaHashArquivo(){
		this("update.info");
	}

	/**
	 * Inicia o processo de criação do arquivo update.info. Este é gerado na raiz
	 * do sistema e o processo de geração consiste na busca de arquivos com a
	 * extensão e pasta passada como parametros. Durante a varredura é escrito
	 * no arquivo update.info as informações do PATH e DATA DE MODIFICAÇÃO de cada
	 * arquivo
	 * 
	 * @param diretorio
	 *            <code>String</code> Raiz da estrutura de pastas onde os arquivos serão percorridas e versionadas
	 *            
	 * @param ext
	 *            <code>String</code> Extensão dos arquivos a serem resgatados
	 *            as informações. (informar * para todos os arquivo)
	 *
	 * TODO Criar um novo método para passar uma lista de extensões ao invés de apenas uma extensão
	 * 
	 * @throws IOException 
	 */
	public void start(String diretorio, String ext) throws Exception{

		// Lista dos arquivos que devem ser versionados
		List<File> lista = captura(diretorio, ext);

		System.out.println("\n\nAboutFiles.gerarArquivoInfo() início");

		for (File file : lista) {
			// Resgata o caminho relativo do arquivo
			String path = file.getAbsolutePath().substring(diretorio.length());

			// Gera a String de hash do arquivo
			System.out.println("\nPATH >> " + path);

			// Gera o hash do arquivo
			String hash = null;
			try{
				hash = new MD5().hashData(file);
			}catch (Exception e) {
				e.printStackTrace();
				hash = "hash_error" + file.hashCode();
			}

			System.out.println("HASH >> " + hash);

			// Persiste a meta-informação com o path relativo do arquivo e o hash
			this.utilProperty.write(path, hash);
		}

		System.out.println("\n\nAboutFiles.gerarArquivoInfo() fim");

	}

	public void start(String diretorio) throws Exception{
		start(diretorio, "*");
	}

	/*
	 * Abaixo os métodos privados
	 */

	/**
	 * Busca recursiva que retorna em uma lista todos os arquivos de uma
	 * determinada extensão encontrados em um diretório e seus subdiretórios.
	 * 
	 * @param diretorio <code>String</code> Caminho do arquivo a ser percorrido
	 * @param ext <code>String</code> Extensão dos arquivos a serem selecionados
	 * @return listaArquivos <code>List<File></code> Arquivos selecionados
	 */
	private List<File> captura(String diretorio, String ext) {
		// Lista para inserir os arquivos validados
		List<File> listaArquivos = new ArrayList<File>();

		// Arquivo a ser consultado
		File temp = new File(diretorio);

		if(temp.isDirectory()){
			// Percorre os arquivos e pastas do diretorio passado como parametro
			for (File file : temp.listFiles()) {
				if (file.isDirectory()) {
					System.out.println("DIRETORIO = " + file.getAbsolutePath());
					listaArquivos.addAll(captura(file.getAbsolutePath(), ext));
				} else if (file.getName().endsWith(ext) || ext.equals("*")) {
					System.out.println("ARQUIVO [" + ext + "] = " + file.getAbsolutePath());
					listaArquivos.add(file);
				} else {
					System.out.println("não é arquivo [" + ext + "] e nem diretório = " + file.getAbsolutePath());
				}
			}
		} else if (temp.getName().endsWith(ext) || ext.equals("*")) {
			System.out.println("ARQUIVO [" + ext + "] = " + temp.getAbsolutePath());
			listaArquivos.add(temp);
		}

		System.out.println("MaquinaHashArquivo.captura() saindo com size = " + listaArquivos.size());

		return listaArquivos;
	}

	/** Método para teste da classe */
	public static void main(String[] args) {
		try {
			new MaquinaHashArquivo().start("/home/reconcavo/workspace/update19/docs/", "txt");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}        
}
